home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / lib / addr / ap_1adr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  14.6 KB  |  543 lines

  1. #include "util.h"
  2. #include "conf.h"
  3. #include "ap.h"
  4. #include "ap_lex.h"
  5.  
  6. /*  ADDRESS PARSER, as per:
  7.  
  8.     "Standard for the Format of ARPA Network Text Messages", D.  Crocker,
  9.     J. Vittal, K. Pogran & D. Henderson, in ARPANET PROTOCOL HANDBOOK, E.
  10.     Feinler & J. Postel (eds), NIC-7104-REV-1, Network Information Center,
  11.     SRI International:  Menlo Park, Ca.  (1978) (NTIS AD-A0038901).
  12.  
  13.     and
  14.  
  15.     "Standard for the Format of Arpa Internet Text Messages", Revised
  16.     by D. Crocker, RFC #822, in INTERNET PROTOCOL TRANSITION WORKBOOK,
  17.     Feinler & J. Postel (eds), Network Information Center, SRI
  18.     International:  Menlo Park, Ca.  (March 1982).
  19.  
  20.     A parsed address is normalized to have routing references placed
  21.     into rfc822-type positioning.
  22.  
  23.     History:
  24.  
  25.     Fall 1977     Bruce Borden:  Initial Design & Coding
  26.     Summer 1979   Dave Crocker:  Completed it & fixed bugs
  27.                  Major reorganization & re-labeling
  28.                  Minor changes to semantics
  29.                  Documentation
  30.     Sept 81       Andy Knutsen   case STPREND -> STPHRSE, to allow comments
  31.                  afterwards
  32.     Sept 81       Dave Crocker   generalized the use of STPHRSE, so that
  33.                  STOKEND occurs only on comma or eof.
  34.                  changed again, to cycle only accepting
  35.                  comments
  36.     Nov 82        Dave Crocker   Converted to accept 822 syntax, while
  37.                  trying also to juggle 733...
  38.     Aug 83        Steve Kille    Fix to STEPER
  39.  
  40.     This module is the real parser, tho it is intended to be co-routined
  41.     with a caller who has something specific to do with ap_1adr's output.
  42.     This is organized so as to make some attempt at limiting core
  43.     consumption.  Fullparse(), however, simply causes a full parse tree to
  44.     be built up in core.
  45.  
  46.     The implementation deviates somewhat from the above specification.
  47.     Deviations and the use of the package are discussed in the companion
  48.     documentation.
  49.  
  50.     The parser's behavior is fairly straightforward.  A singly-linked flat
  51.     list of labelled (lexical) nodes is built up.  Ap_1adr() is used to get
  52.     the next "address segment", which consists of all of the lexical nodes
  53.     up to the end of the next host-phrase (i.e., usually that means up to
  54.     the next comma, semi-colon, or right-angle bracket).
  55.  
  56.     The caller is responsible for initializing state variables, via
  57.     ap_init(), and linking together or using ap_1adr's output segments.
  58.  
  59.     Note that ap_1adr does NOT interpret address text to cause re-directed
  60.     file input.  The caller must do that.  Ap_pshfil() and ap_popfil() can
  61.     be used to save and restore the parse state and acquire the named file.
  62.     The provision for this stacking, given the co-routining, is the reason
  63.     state information is chained through global variables, rather than
  64.     being saved on local (stack) variables.
  65.  
  66.     The amount of input processed on a single call may seem strange.  The
  67.     idea is to try to guess the most common use of the routine.  This is
  68.     presumed to be for address checking, in which acquisition of the MBOX
  69.     and DOMAIN text are most important, with the rest actually being thrown
  70.     away.  It is, of course, possible for the core-limiting heuristic to
  71.     lose if a ridiculous number of groups and personal lists are specified
  72.     in a particular way.  I am assuming that won't happen.
  73. /* */
  74.  
  75. #define STITER     0
  76. #define STINIT     1
  77. #define STECMNT    2
  78. #define STEDONE    3    /* Returned when addresses were NOT found */
  79. #define STEOK      4    /* Returned when addresses were found */
  80. #define STEBAD     5
  81. #define STPHRSE    6
  82. #define STSTPER    7
  83. #define STEPER     8
  84. #define STEGRP     9
  85. #define STDTYPE   10
  86. #define STEDTYPE  11
  87. #define STDOMAIN  12
  88. #define STEDOMAIN 13
  89.  
  90. int  ap_intype = AP_733;          /* default to RFC #733 input           */
  91. int  ap_outtype = AP_822;
  92.                 /* default to RFC #822 output          */
  93.                 /* with little endian domains          */
  94.  
  95.  
  96. int ap_grplev = 0;                /* Group nesting depth                  */
  97. int ap_perlev = 0;                /* <> nesting depth                     */
  98. int ap_routing;                   /* parsing a route                    */
  99.  
  100. LOCFUN ap_7to8();
  101.  
  102. #ifdef DEBUG
  103. #include "ll_log.h"
  104.  
  105. extern LLog *logptr;
  106. extern AP_ptr ap_sqinsert ();
  107. extern char *strdup();
  108. #endif
  109.  
  110. #if DEBUG > 1
  111. int    debug;                    /* True if in debug mode                */
  112. char   *statnam[] =
  113. {
  114.     "Iterate", "Init", "CmntEnd", "DoneEnd", "OKEnd", "BadEnd", "Phrase",
  115.     "Persstrt", "PersEnd", "GrpEnd", "DTypNam", "DTypeE", "Domain",
  116.     "DomainE"
  117. };
  118.  
  119. char   *ptrtab[] =
  120. {
  121.     "Nil", "Etc", "Nxt"
  122. };
  123.  
  124. char   *typtab[] =
  125. {
  126.     "Nil", "Name", "MBox", "Domain", "DataType", "Comment", "Word",
  127.     "Person", "NPersn", "EPersn", "Group", "NGroup", "EGroup", "DomainLit"
  128. };
  129. #endif
  130. /* */
  131.  
  132. ap_1adr ()
  133. {
  134.     struct ap_node basenode;
  135.     AP_ptr ap_sp;        /* Saved ap node ptr                    */
  136.     AP_ptr r822ptr,
  137.        r733prefptr;
  138.     int    got822;
  139.     char    buf[LINESIZE];
  140.     register int    state;
  141.  
  142. #if DEBUG > 1
  143.     if (debug)
  144.     (void) putchar ('\n');
  145. #endif
  146.  
  147.     ap_routing = DONE;
  148.     ap_ninit (&basenode);
  149.     ap_sqinsert (&basenode, APP_ETC, ap_pstrt);
  150.     for (state = STINIT, got822 = FALSE, r733prefptr = (AP_ptr) 0; ;){
  151. #if DEBUG > 1
  152.     if (debug)
  153.         printf ("=>%d (%s)", state,
  154.         (state >= 0 && state <= 13) ? statnam[state] : "BOGUS!");
  155. #endif
  156.     switch (state)
  157.     {
  158.         case STITER:          /* Iteration to get real address        */
  159.         ap_palloc ();
  160.         state = STINIT;   /* just DROP ON THROUGH                 */
  161.         case STINIT:          /* START of parse; empty node           */
  162.         ap_sp = ap_pcur;
  163.         switch (ap_lex (buf)){
  164.             case LV_WORD:
  165.             ap_pfill (APV_WORD, buf);
  166.             state = STPHRSE;
  167.             break;
  168.             case LV_AT:
  169.             if (!got822){
  170.                 got822 = TRUE;
  171.                 r822ptr = ap_pcur;
  172.             }
  173.             ap_routing = OK;
  174. #if DEBUG > 1
  175.             if (debug)
  176.                 printf ("(routing)");
  177. #endif
  178.             state = STDOMAIN;
  179.             break;
  180.             case LV_COLON:
  181.                   /* DATA TYPE start                      */
  182.             state = STDTYPE;
  183.             break;
  184.             case LV_SEMI: /* GROUP LIST end                       */
  185.             state = STEGRP;
  186.             break;
  187.             case LV_GRTR: /* PERSONAL LIST end                    */
  188.             state = STEPER;
  189.             break;
  190.             case LV_LESS: /* allow one angle-bracket, here */
  191.             case LV_FROM: /* FILE source                          */
  192.             ap_pfill (APV_DTYP, "Include");
  193.             state = STITER;
  194.             break;
  195.             case LV_COMMENT:
  196.             ap_pfill (APV_CMNT, buf);
  197.             state = STITER;
  198.             break;
  199.             case LV_COMMA:
  200.             break;    /* ignore null addresses                */
  201.             case LV_EOD:
  202.             if (ap_perlev != 0 || ap_grplev != 0)
  203.                 state = STEBAD;
  204.             else
  205.                 state = STEDONE;
  206.             break;
  207.             default:
  208.             state = STEBAD;
  209.             break;
  210.         }
  211.         continue;
  212.  
  213.  
  214. /* ***************************  ENDING  ********************************* */
  215.  
  216.         case STECMNT:         /* accept comments until end            */
  217.         switch (ap_lex (buf)) {
  218.             case LV_COMMENT:
  219.             ap_pfill (APV_CMNT, buf);
  220.             break;    /* just cycle, accepting comments     */
  221.             case LV_COMMA:
  222.             state = STEOK;
  223.             break;
  224.             case LV_EOD:
  225.             state = STEOK;
  226.             break;
  227.             default:
  228.             state = STEBAD;
  229.             break;
  230.         }
  231.         continue;
  232.  
  233.         case STEDONE:         /* END clean; NO empty nodes?           */
  234. #if DEBUG > 1
  235.         if (debug)
  236.             (void) putchar ('\n');
  237. #endif
  238.         ap_7to8 (r733prefptr, r822ptr);
  239.         return (DONE);
  240.  
  241.         case STEOK:         /* END clean                            */
  242. #if DEBUG > 1
  243.         if (debug)
  244.             (void) putchar ('\n');
  245. #endif
  246.         ap_7to8 (r733prefptr, r822ptr);
  247.         return (OK);
  248.  
  249.         case STEBAD:         /* END error                            */
  250. #if DEBUG > 1
  251.         if (debug)
  252.             (void) putchar ('\n');
  253. #endif
  254.         ap_clear();        /* Experimental, DPK, 7 Aug 84 */
  255.         return (NOTOK);
  256. /*  *********************  GATHER A PHRASE  **************************** */
  257.  
  258.         case STPHRSE:         /* PHRASE continuation; empty node      */
  259.         switch (ap_lex (buf)) {
  260.             case LV_WORD: /* append word to phrase, maybe         */
  261.             ap_padd (APV_WORD, buf);
  262.             break;
  263.             case LV_AT:   /* MAILBOX (name) end                 */
  264.             if (!got822)
  265.                 r822ptr = ap_pcur;
  266.             ap_sqtfix (ap_sp, ap_pcur, APV_MBOX);
  267.             ap_palloc ();
  268.             state = STDOMAIN;
  269.             break;
  270.             case LV_LESS: /* PERSON NAME end                      */
  271.             state = STSTPER;
  272.             break;
  273.             case LV_COLON:
  274.                   /* GROUP NAME end                       */
  275.             if (ap_grplev++ >= 1 && ap_intype == AP_822)
  276.             {        /* may not be nested */
  277. #if DEBUG > 1
  278.                 if (debug)
  279.                 printf ("(intype=%d,ap_grplev=%d)",
  280.                        ap_intype, ap_grplev);
  281. #endif
  282.                 state = STEBAD;
  283.                 break;
  284.             }
  285.             ap_sqtfix (ap_sp, ap_pcur, APV_GRUP);
  286.             ap_sp -> ap_obtype = APV_NGRP;
  287.             state = STITER;
  288.             break;
  289.             case LV_SEMI:
  290.             ap_sqtfix (ap_sp, ap_pcur, APV_MBOX);
  291.             ap_sp -> ap_obtype = APV_MBOX;
  292.             state = STEGRP;
  293.             break;
  294.             case LV_GRTR:
  295.             state = STEPER;
  296.             break;
  297.             case LV_COMMA:
  298.             ap_sqtfix (ap_sp, ap_pcur, APV_MBOX);
  299.             state = STEOK;
  300.             break;
  301.             case LV_EOD:
  302.             ap_sqtfix (ap_sp, ap_pcur, APV_MBOX);
  303.             state = STEOK;
  304.             break;
  305.             case LV_COMMENT:
  306.             ap_pappend (APV_CMNT, buf);
  307.             break;
  308.             default:
  309.             state = STEBAD;
  310.             break;
  311.         }
  312.         continue;
  313.  
  314. /*  ***********************  ADDRESS LISTS  **************************** */
  315.  
  316.         case STSTPER:         /* PERSONAL address list; NO empty node */
  317.         if (ap_perlev++ > 0 && ap_intype == AP_822)
  318.         {        /* may not be nested */
  319. #if DEBUG > 1
  320.             if (debug)
  321.             printf ("(intype=%d,ap_perlev=%d)",
  322.                    ap_intype, ap_perlev);
  323. #endif
  324.             state = STEBAD;
  325.             break;
  326.         }
  327.         ap_routing = OK;
  328.         ap_sqtfix (ap_sp, ap_pcur, APV_PRSN);
  329.         ap_sp -> ap_obtype = APV_NPER;
  330.         state = STITER;
  331.         continue;
  332.  
  333.         case STEPER:
  334.         if (--ap_perlev < 0) {
  335. #if DEBUG > 1
  336.             if (debug)
  337.             printf ("(ap_perlev=%d)", ap_perlev);
  338. #endif
  339.             state = STEBAD;
  340.             break;
  341.         }
  342.         ap_pappend (APV_EPER, (char *) 0);
  343.         ap_palloc ();   /* SEK add storage */
  344.         state = STECMNT; /* allow comments, etc */
  345.         continue;
  346.  
  347.         case STEGRP:
  348.         if (--ap_grplev < 0) {
  349. #if DEBUG > 1
  350.             if (debug)
  351.             printf ("(ap_grplev=%d)", ap_grplev);
  352. #endif
  353.             state = STEBAD;
  354.             break;
  355.         }
  356.         ap_pappend (APV_EGRP, (char *) 0);
  357.         state = STECMNT;
  358.         continue;
  359.  
  360.  
  361. /* **************************  DATA TYPE  ******************************* */
  362.  
  363.         case STDTYPE:          /* DATA TYPE name; empty node           */
  364.         if (ap_intype == AP_822)
  365.         {        /* data types not legal in 822 */
  366. #if DEBUG > 1
  367.             if (debug)
  368.             printf ("(intype=%d)", ap_intype);
  369. #endif
  370.             state = STEBAD;
  371.             break;
  372.         }
  373.         if (ap_lex (buf) != LV_WORD) {
  374.             state = STEBAD;
  375.             continue;
  376.         }
  377.         ap_pfill (APV_DTYP, buf);
  378.         state = STEDTYPE;
  379.                   /* Just drop on through                 */
  380.         case STEDTYPE:         /* DATA TYPE name end; empty node       */
  381.         state = (ap_lex (buf) == LV_COLON)
  382.             ? STITER : STEBAD;
  383.         continue;
  384. /*  *************************  DOMAIN  *********************************** */
  385.  
  386.         case STDOMAIN:        /* DOMAIN/Host; NO empty parse node   */
  387.         switch (ap_lex (buf)) {
  388.             default:
  389.             state = STEBAD;
  390.             continue;
  391.             case LV_COMMENT:
  392.             ap_pappend (APV_CMNT, buf);
  393.             continue;
  394.             case LV_DLIT:
  395.             ap_pappend (APV_DLIT, buf);
  396.             state = STEDOMAIN;
  397.             continue;
  398.             case LV_WORD:
  399.             ap_pfill (APV_DOMN, buf);
  400.             state = STEDOMAIN;
  401.         }                 /* just drop on through                 */
  402.  
  403.         case STEDOMAIN:       /* DOMAIN end; NO empty parse node      */
  404.         switch (ap_lex (buf)) {
  405.             case LV_AT:   /* sequence of HOST's => @ separation   */
  406.                   /* SEK correct here              */
  407.             if (r733prefptr == (AP_ptr) 0)
  408.                 r733prefptr = ap_pcur;
  409.             ap_palloc ();
  410.                  /* node which points to first routing ref */
  411.             state = STDOMAIN;
  412.             break;
  413.             case LV_SEMI:
  414.             state = STEGRP;
  415.             break;
  416.             case LV_GRTR:
  417.             state = STEPER;
  418.             break;
  419.             case LV_COMMA:
  420.             if (ap_routing != DONE)
  421.                 state = STITER;
  422.             else
  423.                 state = STEOK;
  424.             break;
  425.             case LV_EOD:
  426.             if (ap_routing != DONE || 
  427.                 ap_perlev != 0 || ap_grplev != 0)
  428.                 state = STEBAD;
  429.             else
  430.                 state = STEOK;
  431.             break;
  432.             case LV_COMMENT:
  433.             ap_pappend (APV_CMNT, buf);
  434.             break;
  435.             case LV_COLON:
  436.             if (ap_routing != DONE) {
  437.                 ap_routing = DONE;
  438.                 state = STITER;
  439.                 continue;
  440.             }       /* else DROP ON THROUGH */
  441.             default:
  442.             state = STEBAD;
  443.             break;
  444.         }
  445.         continue;
  446.     }
  447.     }
  448. }
  449.  
  450.  
  451.  
  452. LOCFUN
  453. ap_7to8 (r733prefptr, r822ptr)
  454.     AP_ptr r733prefptr,
  455.         r822ptr;
  456. {
  457.     AP_ptr routbase;
  458.     AP_ptr ap;
  459.     char  *perneeded;
  460.  
  461.     if (r733prefptr == (AP_ptr) 0)
  462.     return;               /* don't have to move it to 822 style     */
  463.  
  464. #ifdef DEBUG
  465.     ll_log (logptr, LLOGFTR, "733 ref");
  466. #endif
  467.  
  468.    if (ap_pstrt -> ap_obtype == APV_MBOX) {
  469.     perneeded = strdup (r822ptr -> ap_obvalue);
  470.     ap_pappend (APV_EPER, (char *) 0);
  471.    }
  472.    else
  473.     perneeded = (char *) 0;
  474.  
  475.     routbase = ap_alloc (); /* move the sequence to newroute        */
  476.     while (r733prefptr -> ap_ptrtype != APP_NIL &&
  477.         r733prefptr -> ap_ptrtype != APP_NXT &&
  478.         r733prefptr -> ap_chain != (AP_ptr) 0)
  479.    {
  480.     switch (r733prefptr -> ap_chain -> ap_obtype)
  481.     {
  482.         default:     /* only move domain info */
  483.         goto endit;
  484.  
  485.         case APV_CMNT:
  486.         if (routbase -> ap_chain != (AP_ptr) 0)
  487.         {           /* try to append, not prepend, comments */
  488. #ifdef DEBUG
  489.             ll_log (logptr, LLOGFTR,
  490.             "comment appended'%s'", r733prefptr -> ap_chain -> ap_obvalue);
  491. #endif
  492.             ap_move (routbase -> ap_chain, r733prefptr);
  493.             continue;
  494.         }           /* else DROP ON THROUGH */
  495.         case APV_DLIT:
  496.         case APV_DOMN:
  497. #ifdef DEBUG
  498.         ll_log (logptr, LLOGFTR,
  499.             "val='%s'", r733prefptr -> ap_chain -> ap_obvalue);
  500. #endif
  501.         ap_move (routbase, r733prefptr);
  502.         continue;
  503.     }
  504.     }
  505.  
  506. endit:
  507.             /* treatment here depends on whether we have an */
  508.             /*  822 route already.  Note that 822 pointer is*/
  509.             /*  NOT easy,  as an easy pointer was too hard! */
  510.             /* SEK need to copy first part of route */
  511.             /* to r822ptr                       */
  512.    if (r822ptr -> ap_obtype != APV_DOMN && r822ptr -> ap_obtype != APV_DLIT) {
  513.     ap_insert (r822ptr, APP_ETC,
  514.            ap_new (r822ptr -> ap_obtype,
  515.                  r822ptr -> ap_obvalue));
  516.     free (r822ptr -> ap_obvalue);
  517.     ap_fllnode (r822ptr, routbase -> ap_chain -> ap_obtype,
  518.                     routbase -> ap_chain -> ap_obvalue);
  519.     ap_sqinsert (r822ptr, APP_ETC, routbase -> ap_chain -> ap_chain);
  520.                /* add it before local-part         */
  521.     ap_free (routbase);
  522.     ap_free (routbase -> ap_chain);
  523.    } else {
  524.     ap = r822ptr;
  525.     while (ap -> ap_chain -> ap_obtype == APV_DOMN ||
  526.             ap -> ap_chain -> ap_obtype == APV_DLIT)
  527.        ap = ap -> ap_chain;
  528.     ap_sqinsert (ap, APP_ETC, routbase -> ap_chain);
  529.    }
  530.  
  531.  
  532.    if (perneeded != 0)          /* SEK need to kludge person name       */
  533.    {
  534.     ap_insert (r822ptr, APP_ETC,
  535.            ap_new (r822ptr -> ap_obtype,
  536.                  r822ptr -> ap_obvalue));
  537.     free (r822ptr -> ap_obvalue);
  538.     ap_fllnode (r822ptr, APV_NPER, perneeded);
  539.     free (perneeded);
  540.    }
  541. }
  542.  
  543.